package tm.testing;



import java.util.HashMap;

import javax.swing.ImageIcon;

import org.lex.game.StrategicHandlerDefaults;
import org.lex.input.StrategicCameraEffects;
import org.lex.input.StrategicHandler;
import org.lex.input.effects.HeightMap;
import org.lex.input.mouse.MouseBindingManager;
import org.lex.input.mouse.MouseManager;
import org.lex.input.mouse.component.CombinedMouse;


import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingSphere;
import com.jme.image.Texture;
import com.jme.input.FirstPersonHandler;
import com.jme.input.InputHandler;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.input.MouseInputListener;
import com.jme.input.NodeHandler;
import com.jme.input.controls.binding.MouseButtonBinding;
import com.jme.light.DirectionalLight;
import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.CameraNode;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.TriMesh;
import com.jme.scene.Spatial.CullHint;
import com.jme.scene.Spatial.LightCombineMode;
import com.jme.scene.shape.Box;
import com.jme.scene.shape.Quad;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.CullState;
import com.jme.scene.state.FogState;
import com.jme.scene.state.TextureState;
import com.jme.util.TextureManager;
import com.jmex.terrain.TerrainPage;
import com.jmex.terrain.util.ImageBasedHeightMap;

/**
 * <code>TestTerrainPage</code>
 *
 * @author Mark Powell
 * @version $Id: TestTerrainPage.java 4130 2009-03-19 20:04:51Z blaine.dev $
 */
public class TestOne extends SimpleGame {

  private CameraNode camNode;
  private TerrainPage page;
  private Node terrainNode;
  private float farPlane = 10000.0f;
  
  
	private String cmdToggleFilters = "toggleFilters";
	private String cmdNextCursor = "nextCursor";
	private String cmdChangeLocation = "changeLocation";
	private String cmdFollowObject = "followObject";
	private String cmdFollowObjectRotation = "followObjectRotation";
	private String cmdFollowObjectAligned = "followObjectAligned";
	private String cmdToggleRunnerMove = "toggleRunnerMove";
	private String cmdToggleHeightOffset = "toggleHeightOffset";
	private String cmdToggleHandler = "toggleHandler";
	private String cmdFlyToOrigin = "flyToOrigin";
	private MouseBindingManager mouseBinding;
	private String mbLeftClick = "leftClick";
	private FirstPersonHandler firstPersonHandler;
	private String defaultCursor = "defaultCursor";
	private String attackCursor = "attackCursor";
	private String selectCursor = "selectCursor";
	private StrategicHandler strategicHandler;
	private StrategicCameraEffects camEffects;
	private Quad minimap;
	private float minimapWidth = 200;
	private float minimapHeight = 200;
	private Vector2f mapLocation = new Vector2f();
	private float modifiedHeight = 50;
	private String[] cursors = {defaultCursor, attackCursor, selectCursor};
	private int currentCursorIndex;

	

  private KeyBindingManager keyboard;
  
  private MapGrid mapGrid;
  private int gridSize = 80;
  private int gridElements = 64;
  
  
  private Vehicle van;
  
  

  /**
   * Entry point for the test,
   *
   * @param args
   */
  public static void main(String[] args) {
    TestOne app = new TestOne();
    app.setConfigShowMode(ConfigShowMode.AlwaysShow);
    app.start();
  }

  /**
   * builds the trimesh.
   *
   * @see com.jme.app.SimpleGame#initGame()
   */
  protected void simpleInitGame() {
	  setupControls();
	  setupInput();
	  setupMisc();
	  
	  
	  mapGrid = new MapGrid(gridSize, gridElements, rootNode);
	  
	  Road road = new Road("road", mapGrid);
	  road.addField(new Coordinate(31,28));
	  road.addField(new Coordinate(31,29));
	  road.addField(new Coordinate(31,31));
	  road.addField(new Coordinate(31,32));
	  road.addField(new Coordinate(32,32));
	  road.addField(new Coordinate(33,32));
	  road.addField(new Coordinate(34,32));
	  road.addField(new Coordinate(35,32));
	  road.addField(new Coordinate(35,33));
	  road.addField(new Coordinate(35,34));
	  road.addField(new Coordinate(36,34));
	  road.addField(new Coordinate(37,34));
	  road.addField(new Coordinate(38,34));
	  road.addField(new Coordinate(38,33));
	  road.addField(new Coordinate(38,32));
	  road.addField(new Coordinate(38,31));
	  road.addField(new Coordinate(38,30));
	  road.addField(new Coordinate(37,30));
	  road.addField(new Coordinate(36,30));
	  road.addField(new Coordinate(35,30));
	  road.addField(new Coordinate(34,30));
	  road.addField(new Coordinate(33,30));
	  road.addField(new Coordinate(32,30));
	  road.addField(new Coordinate(31,30));
	  road.addField(new Coordinate(30,30));
	  road.addField(new Coordinate(33,31));
	  road.updateCurve();
	  road.computeSpatials();
	  road.showGeometry();
	  
	  BusRoute busroute = new BusRoute("BusRoute", mapGrid, road);
	  busroute.addSegment(new Coordinate(32,32), Road.RIGHT);
	  busroute.addSegment(new Coordinate(33,32), Road.RIGHT);
	  busroute.addSegment(new Coordinate(34,32), Road.RIGHT);
	  busroute.addSegment(new Coordinate(35,32), Road.RIGHT);
	  busroute.addSegment(new Coordinate(35,33), Road.RIGHT);
	  busroute.addSegment(new Coordinate(35,34), Road.RIGHT);
	  busroute.buildCurve();
	  //only for debug
	  rootNode.attachChild(busroute.getCurve());
	  
	  
	  TriMesh box = new Box("Toll",new Vector3f(0,0,0), 5,5,5);
	  box.setModelBound(new BoundingSphere());
	  box.updateModelBound();
	  try {
		box.setLocalTranslation(mapGrid.getElementCoord(road.getCoordinateAt(0).getX(),road.getCoordinateAt(0).getY(),150.0f));
	} catch (MapElementIndexOutOfBoundsException e1) {
		// TODO Auto-generated catch block
		e1.printStackTrace();
	}
	
	  van = new Vehicle("VAN", busroute.getCurve(), box);
	  van.setMotionState(Vehicle.DRIVING);
	  rootNode.attachChild(van.getSpatial());
	  
	
	
	
	  terrainNode = new Node();
      rootNode.setRenderQueueMode(Renderer.QUEUE_OPAQUE);
     
      
	  DirectionalLight dl = new DirectionalLight();
	  dl.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
	  dl.setDirection(new Vector3f(1, -0.5f, 1));
	  dl.setEnabled(true);
	  lightState.attach(dl);
	
	  cam.setFrustumPerspective(45.0f, (float) display.getWidth()
			  / (float) display.getHeight(), 1f, farPlane);
	  cam.setLocation(new Vector3f(-320, 80, -270));
	  cam.lookAt(new Vector3f(0, 0, 0), Vector3f.UNIT_Y);
	  cam.update();
	
	  camNode = new CameraNode("Camera Node", cam);
	  camNode.setLocalTranslation(new Vector3f(0, 250, -20));
	  camNode.updateWorldData(0);
	  input = new NodeHandler(camNode, 150, 1);
	  rootNode.attachChild(camNode);
	  display.setTitle("Terrain Test");
	  display.getRenderer().setBackgroundColor(new ColorRGBA(0.5f,0.5f,0.5f,1));
	
	  DirectionalLight dr = new DirectionalLight();
	  dr.setEnabled(true);
	  dr.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
	  dr.setAmbient(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f));
	  dr.setDirection(new Vector3f(0.5f, -0.5f, 0).normalizeLocal());
	
	  CullState cs = display.getRenderer().createCullState();
	  cs.setCullFace(CullState.Face.Back);
	  cs.setEnabled(true);
	  rootNode.setRenderState(cs);
	
	  lightState.attach(dr);
	    
	  ImageIcon image = new ImageIcon(TestOne.class.getClassLoader().getResource("data/textures/testterrain.png"));
	  
	  
	  ImageBasedHeightMap heightMap = new ImageBasedHeightMap(image.getImage());
	  Vector3f terrainScale = new Vector3f(10,1,10);
	  heightMap.setHeightScale( 0.001f);
	  page = new TerrainPage("Terrain", 33, heightMap.getSize(), terrainScale,
			  					heightMap.getHeightMap());
	
	  page.setDetailTexture(1, gridElements);
	  terrainNode.attachChild(page);
	    
	  Texture testgrass = TextureManager.loadTexture(TestOne.class.getClassLoader().
	            getResource(
	                    "data/textures/nicegrass.jpg"),
	                                                        Texture.MinificationFilter.Trilinear,
	                                                        Texture.MagnificationFilter.Bilinear);
	  testgrass.setScale(new Vector3f(90.0f,90.0f,1.0f));
	    
	
	  TextureState ts = display.getRenderer().createTextureState();
	  ts.setEnabled(true);
	
	    
	  ts.setTexture(testgrass, 0);
	  testgrass.setWrap(Texture.WrapMode.Repeat);
	  
	
	  Texture t2 = TextureManager.loadTexture(TestOne.class.getClassLoader().
	                                            getResource(
	        "data/textures/Untitled.png"),
	                                            Texture.MinificationFilter.Trilinear,
	                                            Texture.MagnificationFilter.Bilinear);
	  ts.setTexture(t2, 1);
	  t2.setWrap(Texture.WrapMode.Repeat);
	
	
	  testgrass.setApply(Texture.ApplyMode.Combine);
	  testgrass.setCombineFuncRGB(Texture.CombinerFunctionRGB.Modulate);
	  testgrass.setCombineSrc0RGB(Texture.CombinerSource.CurrentTexture);
	  testgrass.setCombineOp0RGB(Texture.CombinerOperandRGB.SourceColor);
	  testgrass.setCombineSrc1RGB(Texture.CombinerSource.PrimaryColor);
	  testgrass.setCombineOp1RGB(Texture.CombinerOperandRGB.SourceColor);
	  
	
	  t2.setApply(Texture.ApplyMode.Combine);
	  t2.setCombineFuncRGB(Texture.CombinerFunctionRGB.AddSigned);
	  t2.setCombineSrc0RGB(Texture.CombinerSource.CurrentTexture);
	  t2.setCombineOp0RGB(Texture.CombinerOperandRGB.SourceColor);
	  t2.setCombineSrc1RGB(Texture.CombinerSource.Previous);
	  t2.setCombineOp1RGB(Texture.CombinerOperandRGB.SourceColor);
	  terrainNode.setRenderState(ts);
	
	  FogState fogState = display.getRenderer().createFogState();
	  fogState.setDensity(1.0f);
	  fogState.setEnabled(true);
	  fogState.setColor(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
	  fogState.setEnd(farPlane);
	  fogState.setStart(farPlane / 10.0f);
	  fogState.setDensityFunction(FogState.DensityFunction.Linear);
	  fogState.setQuality(FogState.Quality.PerVertex);
	  terrainNode.setRenderState(fogState);
	  rootNode.attachChild(terrainNode);
	  
	  
	  
	  
  }
  
  protected void cameraPerspective() {
      cam.setFrustumPerspective( 60.0f, (float) display.getWidth()
              / (float) display.getHeight(), 1, 1500 );
      cam.setParallelProjection( false );
      cam.update();
  }

  
  
  protected void simpleUpdate() {
	 van.update();
		if (strategicHandler.isEnabled()) {
			/*
			 * Remember to update your cursor every frame. You will want to
			 * do this, because after you do mouse picking you can choose
			 * differet cursors based on the result of the mouse pick.
			 * 
			 * Example: you can set a different cursor when the mouse is
			 * hovering over an enemy vs the default cursor.
			*/
			
			 strategicHandler.useCursor(cursors[currentCursorIndex]);
		}

			
  }
  
  
  public void setupControls() {
	keyboard = KeyBindingManager.getKeyBindingManager();
	
	keyboard.add(cmdToggleFilters, KeyInput.KEY_F);
	keyboard.add(cmdNextCursor, KeyInput.KEY_C);
	keyboard.add(cmdChangeLocation, KeyInput.KEY_L);
	keyboard.add(cmdFollowObject, KeyInput.KEY_Z);
	keyboard.add(cmdFollowObjectRotation, KeyInput.KEY_X);
	keyboard.add(cmdFollowObjectAligned, KeyInput.KEY_V);
	keyboard.add(cmdToggleRunnerMove, KeyInput.KEY_SPACE);
	keyboard.add(cmdToggleHeightOffset, KeyInput.KEY_H);
	keyboard.add(cmdToggleHandler, KeyInput.KEY_TAB);
	keyboard.add(cmdFlyToOrigin, KeyInput.KEY_NUMPAD0);
	
	mouseBinding = MouseBindingManager.get();
	mouseBinding.addCommand(mbLeftClick, MouseButtonBinding.LEFT_BUTTON);
  }
  
	@SuppressWarnings("unchecked")
	public void setupInput() {
		firstPersonHandler = (FirstPersonHandler) input;
		firstPersonHandler.setEnabled(false);
		
		input = new InputHandler();
		input.addToAttachedHandlers(firstPersonHandler);
		
		MouseManager mouseManager = new MouseManager(CombinedMouse.get());
		mouseManager.registerWithInputHandler(input);
		statNode.attachChild(mouseManager.getMouse().getMouseSpatial());
		mouseManager.setMousePosition(
				display.getWidth()/2, display.getHeight()/2);
		
		mouseManager.setCursor(defaultCursor,
				"org/lex/cursors/goldenarrow_v2/default.cursor");
		mouseManager.setCursor(attackCursor,
				"org/lex/cursors/goldenarrow_v2/spinning.cursor");
		mouseManager.setCursor(selectCursor,
				"org/lex/cursors/goldenarrow_select/default.cursor");
		
		HeightMap heightMap = new HeightMap() {
			public float getHeightAt(Vector3f location) {
				float height = page.getHeight(location);
				if (Float.isNaN(height)) height = 0;
				return height;
			}
		};
		strategicHandler = new StrategicHandler(
				cam, mouseManager, heightMap);
		camEffects = new StrategicCameraEffects(strategicHandler);
		strategicHandler.setCameraEffects(camEffects);
		input.addToAttachedHandlers(strategicHandler);

		
		strategicHandler.updateProperties(
				StrategicHandlerDefaults.getCustomConfig());
		
		HashMap cursors = new HashMap();
		cursors.put(StrategicHandler.CURSOR_ROTATE,
				"org/lex/cursors/goldenarrow_rotate/default.cursor");
		cursors.put(StrategicHandler.CURSOR_SCROLL_UP,
				"org/lex/cursors/goldenscroll_up/default.cursor");
		cursors.put(StrategicHandler.CURSOR_SCROLL_UPLEFT,
		"org/lex/cursors/goldenscroll_upleft/default.cursor");
		strategicHandler.updateCursors(cursors);
		
		/*
		// this is how to set cursors via setters
			strategicHandler.getMouseManager().setCursor(
				StrategicHandler.CURSOR_ROTATE,
				Cursor.load(this.getClass().getClassLoader().getResource(
					"org/lex/cursors/goldenarrow.car"),
				"spinning.cursor"));
		*/
	}
	
	public void setupMisc() {
        
		minimap = new Quad("myQuad", minimapWidth, minimapHeight);
		minimap.setLocalTranslation(minimapWidth/2 + 5, minimapHeight/2 + 20, 0);
        minimap.setRenderQueueMode(Renderer.QUEUE_ORTHO);
        minimap.setCullHint(CullHint.Never);
        minimap.setLightCombineMode(LightCombineMode.Off);
        minimap.setTextureCombineMode(Spatial.TextureCombineMode.Off);
        minimap.setDefaultColor(new ColorRGBA(ColorRGBA.white));
        minimap.getDefaultColor().a = 0.5f;
        BlendState as = display.getRenderer().createBlendState();
        as.setBlendEnabled(true);
		as.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
		as.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
		as.setTestEnabled(true);
		as.setTestFunction(BlendState.TestFunction.GreaterThan);
		as.setEnabled(true);
		minimap.setRenderState(as);
        statNode.attachChild(minimap);
       
	}


	@Override
	protected void updateInput() {
		super.updateInput();
		

		if (keyboard.isValidCommand(cmdChangeLocation, false)){
			strategicHandler.setWorldTranslation(0, 0, 0);
		}
		if (keyboard.isValidCommand(cmdToggleHeightOffset, false)){
			float height = strategicHandler.getScrollingPlane().getHeight();
			if (height == modifiedHeight) height = 0;
			else height = modifiedHeight;
			
			strategicHandler.getScrollingPlane().setHeight(height);
		}
		
		
		if (keyboard.isValidCommand(cmdToggleHandler, false)) {
			if (strategicHandler.isEnabled()) {
				strategicHandler.setEnabled(false);
				strategicHandler.clearFilterEffects();
				strategicHandler.getMouseManager().getMouse().disable();
				firstPersonHandler.setEnabled(true);
			} else {
				firstPersonHandler.setEnabled(false);
				strategicHandler.setEnabled(true);
				strategicHandler.getMouseManager().getMouse().enable();
				camEffects.takeOverCamera();
			}
		}
		
		if (keyboard.isValidCommand(cmdFlyToOrigin, false)) {
			if (!strategicHandler.isEnabled()) {
				firstPersonHandler.setEnabled(false);
				strategicHandler.setEnabled(true);
				strategicHandler.getMouseManager().getMouse().enable();
			}
			camEffects.flyToLocation(Vector3f.ZERO);
		}
		
		if (mouseBinding.isValidCommand(mbLeftClick, false)) {
			Vector2f mousePosition =
				strategicHandler.getMouseManager().getMousePosition();
			
			mapLocation.x = (mousePosition.x - minimap.getLocalTranslation().x
						+ minimapWidth/2)/minimapWidth;
			mapLocation.y = (mousePosition.y - minimap.getLocalTranslation().y
						+ minimapHeight/2)/minimapHeight;
			
			if (mapLocation.x >= 0 && mapLocation.x <= 1
					&& mapLocation.y >= 0 && mapLocation.y <= 1)
			{
				mapLocation.x = mapLocation.x*2500 - 1250;
				mapLocation.y = mapLocation.y*2500 - 1250;
				
				if (!strategicHandler.isEnabled()) {
					firstPersonHandler.setEnabled(false);
					strategicHandler.setEnabled(true);
					strategicHandler.getMouseManager().getMouse().enable();
				}
				camEffects.flyToLocation(mapLocation);
			}
		}
	}


  
  
}


